using System;
using System.Xml;
using System.Collections.Generic;
using System.Reflection;
using System.Globalization;
using System.IO;

namespace Dida.Test
{
	public class XmlReportWriter : ITestResultListener
	{
		XmlWriter writer;
		int numFailures;
		bool tooManyTagWritten;

		class Iteration
		{
			public int index;
			public IList<ParamValue> paramValues;

			public List<Failure> failures = new List<Failure>();
		}
		Iteration curIteration = null;

		struct Failure
		{
			public MethodInfo method;
			public string message;
		}

		public XmlReportWriter()
		{
		}

		public void Begin(ProgressSegment fullProgressSegment)
		{
			XmlWriterSettings writerSettings = new XmlWriterSettings();
			writerSettings.Indent = true;
			writer = XmlWriter.Create(new FileStream("c:/test.xml",FileMode.Create), writerSettings);

			writer.WriteStartElement("TestResult");
		}

		public void End()
		{
			writer.WriteEndElement();
			((IDisposable)writer).Dispose();
			writer = null;
		}

		public void BeginTest(UnitTest test, ProgressSegment testProgress)
		{
			writer.WriteStartElement("Test");
			writer.WriteAttributeString("name", test.Name);
		}

		public void EndTest(UnitTest test)
		{
			writer.WriteEndElement();
		}

		public void BeginRunner(RunnerStateInfo stateInfo)
		{
			writer.WriteStartElement("Runner");
			writer.WriteAttributeString("name", stateInfo.Runner.Name);
			
			numFailures = 0;
			tooManyTagWritten = false;
		}

		public void EndRunner(RunnerStateInfo stateInfo)
		{
			writer.WriteEndElement();
		}

		public void BeginIteration(IterationStateInfo stateInfo)
		{
			curIteration = new Iteration();
			curIteration.index = stateInfo.IterationIndex;
			curIteration.paramValues = stateInfo.ParamValues;
		}

		public void EndIteration(IterationStateInfo stateInfo)
		{
			if (curIteration.failures.Count != 0)
			{
				writer.WriteStartElement("Iteration");
				writer.WriteAttributeString("index",stateInfo.IterationIndex.ToString());

				writer.WriteStartElement("ParamValues");
				foreach (ParamValue paramValue in curIteration.paramValues)
				{
					writer.WriteStartElement("Param");
					writer.WriteAttributeString("name", paramValue.Name);

					if (paramValue.Value is IConvertible)
					{
						IConvertible convertable = (IConvertible)paramValue.Value;
						writer.WriteAttributeString("value", convertable.ToString(NumberFormatInfo.InvariantInfo));
					}
					else
					{
						writer.WriteAttributeString("value", paramValue.Value.ToString());
					}

					writer.WriteEndElement();
				}
				writer.WriteEndElement();

				writer.WriteStartElement("Failures");
				foreach (Failure failure in curIteration.failures)
				{
					writer.WriteStartElement("FailedMethod");
					writer.WriteAttributeString("methodName", failure.method.DeclaringType.FullName + "." + failure.method.Name);
					writer.WriteString(failure.message);
					writer.WriteEndElement();
				}
				writer.WriteEndElement();
				writer.WriteEndElement();
			}

			curIteration = null;
		}

		public void ReportSuccess(TestMethodResult result)
		{
		}

		public void ReportFailure(TestMethodResult result)
		{
			Failure curFailure = new Failure();
			curFailure.method = result.MethodInfo;
			curFailure.message = result.Message;
			curIteration.failures.Add(curFailure);
		}

		public void ReportFailure(int index,ParamValue[] paramValues,string message)
		{
			if (numFailures >= 100)
			{
				if (!tooManyTagWritten)
				{
					writer.WriteStartElement("TooMany");
					writer.WriteEndElement();

					tooManyTagWritten = true;
				}
				return;
			}

			writer.WriteStartElement("Failed");
			writer.WriteAttributeString("index",index.ToString());

			if(message != null)
			{
				writer.WriteStartElement("Message");
				writer.WriteString(message);
				writer.WriteEndElement();
			}

			foreach (ParamValue paramValue in paramValues)
			{
				writer.WriteStartAttribute("Param");
				writer.WriteAttributeString("name", paramValue.Name);
				writer.WriteAttributeString("value", paramValue.Value.ToString());
				writer.WriteEndElement();
			}

			writer.WriteEndElement();

			numFailures++;
		}
	}
}
